package com.galfins.gogpsextracts.Gal;

import android.util.Log;

import com.galfins.gogpsextracts.EphemerisResponse;
import com.galfins.gogpsextracts.GnssEphemeris;
import com.galfins.gogpsextracts.Iono;
import com.galfins.gogpsextracts.NavigationProducer;
import com.galfins.gogpsextracts.SatellitePosition;

import java.util.ArrayList;


/**
 * <p>
 * Class for parsing RINEX navigation files
 * </p>
 *
 * @author Eugenio Realini, Cryms.com
 * <p>
 * <p>
 * adapted for Galileo system by: Sebastian Ciuban
 */
public class RinexNavigationParserGalileo extends EphemerisSystemGalileo implements NavigationProducer {
    private final String TAG = this.getClass().getSimpleName();

    private ArrayList<EphGalileo> eph = new ArrayList<EphGalileo>(); /* GPS broadcast ephemerides */
    //private double[] iono = new double[8]; /* Ionosphere model parameters */
    private Iono iono = null; /* Ionosphere model parameters */
    //	private double A0; /* Delta-UTC parameters: A0 */
    //	private double A1; /* Delta-UTC parameters: A1 */
    //	private double T; /* Delta-UTC parameters: T */
    //	private double W; /* Delta-UTC parameters: W */
    //	private int leaps; /* Leap seconds */

    public RinexNavigationParserGalileo(EphemerisResponse ephResponse) {
        for (GnssEphemeris eph : ephResponse.ephList) {
            if (eph instanceof GalEphemeris) {
                this.eph.add(new EphGalileo((GalEphemeris) eph));
            }
        }
        this.iono = new Iono(ephResponse.ionoProto2);
    }

    /**
     * @param unixTime
     * @param satID
     * @return Reference ephemeris set for given time and satellite
     */
    public EphGalileo findEph(long unixTime, int satID, char satType) {

        long dt = 0;
        long dtMin = 0;
        long dtMax = 0;
        long delta = 0;
        EphGalileo refEph = null;

        //long gpsTime = (new Time(unixTime)).getGpsTime();

        for (int i = 0; i < eph.size(); i++) {
            // Find ephemeris sets for given satellite
            if (eph.get(i).getSatID() == satID && eph.get(i).getSatType() == satType) {
                // Consider BeiDou time (BDT) for BeiDou satellites (14 sec difference wrt GPS time)
                if (satType == 'C') {
                    delta = 14000;
                    unixTime = unixTime - delta;
                }
                // Compare current time and ephemeris reference time
                dt = Math.abs(eph.get(i).getRefTime().getMsec() - unixTime /*getGpsTime() - gpsTime*/) / 1000;
                // If it's the first round, set the minimum time difference and
                // select the first ephemeris set candidate; if the current ephemeris set
                // is closer in time than the previous candidate, select new candidate
                if (refEph == null || dt < dtMin) {
                    dtMin = dt;
                    refEph = eph.get(i);
                }
            }
        }

        if (refEph == null)
            return null;

        if (refEph.getSvHealth() != 0) {
            return EphGalileo.UnhealthyEph;
        }

        switch (refEph.getSatType()) {
            case 'R':
                dtMax = 950;
            case 'J':
                dtMax = 3600;
            default:
                dtMax = 7200;
        }

        if (dtMin > dtMax) {
            refEph = null;
        }

        return refEph;
    }

    public Iono getIono(long unixTime) {
        return iono;
    }

    public boolean isTimestampInEpocsRange(long unixTime) {
        return eph.size() > 0/* &&
				eph.get(0).getRefTime().getMsec() <= unixTime /*&&
		unixTime <= eph.get(eph.size()-1).getRefTime().getMsec() missing interval +epochInterval*/;
    }

    public SatellitePosition getGalileoSatPosition(long unixTime, double range, int satID, char satType, double receiverClockError) {
        //long unixTime = obs.getRefTime().getMsec();
        //double range = obs.getSatByIDType(satID, satType).getPseudorange(0);

        if (range == 0)
            return null;

        EphGalileo eph = findEph(unixTime, satID, satType);
        //if( eph.equals( EphGalileo.UnhealthyEph ))
        //return SatellitePosition.UnhealthySat;

        if (eph == null) {
            Log.e(TAG, "getGalileoSatPosition: Ephemeris failed to load...");
            return null;
        }

        //			char satType = eph.getSatType();

        SatellitePosition sp = computePositionGalileo(unixTime, range, satID, satType, eph, receiverClockError);
        //			SatellitePosition sp = computePositionGps(unixTime, satType, satID, eph, range, receiverClockError);
        //if(receiverPosition!=null) earthRotationCorrection(receiverPosition, sp);

        return sp;// new SatellitePosition(eph, unixTime, satID, range);

    }

    public SatellitePosition getGalileoSatVelocities(long unixTime, double range, int satID, char satType, double receiverClockError) {
        //long unixTime = obs.getRefTime().getMsec();
        //double range = obs.getSatByIDType(satID, satType).getPseudorange(0);

        if (range == 0)
            return null;

        EphGalileo eph = findEph(unixTime, satID, satType);
        if (eph.equals(EphGalileo.UnhealthyEph))
            return SatellitePosition.UnhealthySat;

        if (eph != null) {

            SatellitePosition sv = computePositionSpeedGalileo(unixTime, range, satID, satType, eph, receiverClockError);


            return sv;
        }
        return null;
    }
}
